package com.atguigu.test.config;

import com.atguigu.test.mvc.editor.MyMessageConverter;
import com.atguigu.test.mvc.my.MyRequestMappingHandlerAdapter;
import com.atguigu.test.mvc.my.MyTokenHandlerMethodArgumentResolver;
import com.atguigu.test.mvc.view.MyView;
import com.atguigu.test.po.LifeCycleBean;
import com.atguigu.test.processor.MyLifeCycleBeanPostProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistrarBeanPostProcessor;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zp
 * @version 1.0
 * @description: springWeb 配置类
 * 排除Configuration和ControllerAdvice注解的类 防止冲突
 * ControllerAdvice不排除 容易提取处理异常 无效果
 * @date 2022/12/14 19:39
 */
@Slf4j
@Configuration
@ComponentScan(value = "com.atguigu.test.mvc",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION
                , classes = {Configuration.class}),@ComponentScan.Filter(type = FilterType.ANNOTATION
                , classes = {ControllerAdvice.class})})
public class SpringWebConfig {
    /**
     * @description:  注入声明之前增强器 打印生命周期的环节
     * @author zp
     * @date: 2022/12/14 20:26
     * @return MyLifeCycleBeanPostProcessor
     */
    @Bean
    public MyLifeCycleBeanPostProcessor myLifeCycleBeanPostProcessor(){
        return new MyLifeCycleBeanPostProcessor();
    }
    /**
     * @description:  执行生命周期的bean
     * @author zp
     * @date: 2022/12/14 20:26
     * @return LifeCycleBean
     */
    @Bean
    public LifeCycleBean lifeCycleBean(){
        return new LifeCycleBean();
    }
    /**
     * @description:  配置web容器的环境 这里设置tomcat的web环境
     * @author zp
     * @date: 2022/12/14 19:49
     * @return ServletWebServerFactory
     */
    @Bean
    public ServletWebServerFactory servletWebServerFactory(){
        return new TomcatServletWebServerFactory();
    }
    /**
     * @description:  注入一个默认的servlet控制器 也是程序访问的入口
     * @author zp
     * @date: 2022/12/14 19:49
     * @return DispatcherServlet
     */
    @Bean
    public DispatcherServlet dispatcherServlet(){
      return  new DispatcherServlet();
    }
    /**
     * @description:  控制器和路径的绑定类 绑定一个路径
     * @author zp
     * @date: 2022/12/14 19:50
     * @param dispatcherServlet
     * @return DispatcherServletRegistrationBean
     */
    @Bean
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet){
        return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
    }
    /**
     * @description:  设置一个请求 方便测试
     * @author zp
     * @date: 2022/12/14 19:53
     * @return Controller
     */
    @Bean("/hello")
    public Controller controller(){
        return (httpServletRequest, httpServletResponse) -> {
            httpServletResponse.getWriter().println("hello");
            return null;
        };
    }

    /**
     * @description:  默认注入的RequestMappingHandlerMapping的是属于DispatcherServlet的一个属性
     * 无法从容器中直接获取 所以需要通过bean手动注入的方式注入对象 方便直接从容器中获取元素
     * @author zp
     * @date: 2022/12/31 16:50
     * @return RequestMappingHandlerMapping
     */
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(){
        return new RequestMappingHandlerMapping();
    }

    /**
     * @description:  默认注入的RequestMappingHandlerAdapter的是属于DispatcherServlet的一个属性
     * 无法从容器中直接获取 所以需要通过bean手动注入的方式注入对象 方便直接从容器中获取元素
     * @author zp
     * @date: 2023/1/1 15:52
     * @return RequestMappingHandlerAdapter
     */
    @Bean
    public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter(){
        MyTokenHandlerMethodArgumentResolver myTokenHandlerMethodArgumentResolver = new MyTokenHandlerMethodArgumentResolver();


        MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter = new MyRequestMappingHandlerAdapter();
        List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
//        List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
//        returnValueHandlers.add(myYamlHandlerMethodReturnValueHandler);
//        returnValueHandlers.add(myPrivacyEncryptHandlerMethodReturnValueHandler);
        argumentResolvers.add(myTokenHandlerMethodArgumentResolver);
        // 添加自定义的参数解析器
        myRequestMappingHandlerAdapter.setCustomArgumentResolvers(argumentResolvers);
        // 添加自定义的返回值解析器
        myRequestMappingHandlerAdapter.getReturnValueHandlers();
        // 添加 JSON消息转换器
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(myRequestMappingHandlerAdapter.getMessageConverters());
        messageConverters.add(new MappingJackson2HttpMessageConverter());
        // 添加自定义的消息解析器
        messageConverters.add(new MyMessageConverter());

        myRequestMappingHandlerAdapter.setMessageConverters(messageConverters);
        // myRequestMappingHandlerAdapter.setReturnValueHandlers(returnValueHandlers);
        return myRequestMappingHandlerAdapter;
    }
    /**
     * @description:  修改tomcat 默认服务器错误地址
     * @author zp
     * @date: 2023/1/15 15:46
     * @return ErrorPageRegistrar
     */
    @Bean
    public ErrorPageRegistrar errorPageRegistrar(){
        return servletWebServerFactory -> servletWebServerFactory.addErrorPages(new ErrorPage("/error"));
    }
    /**
     * @description:  添加对应的bean后置处理器
     * @author zp
     * @date: 2023/1/15 15:51
     * @return ErrorPageRegistrarBeanPostProcessor
     */
    @Bean
    public ErrorPageRegistrarBeanPostProcessor errorPageRegistrarBeanPostProcessor(){
        return new ErrorPageRegistrarBeanPostProcessor();
    }
    /**
     * @description:  配置springboot当中配置好的响应页面
     * @author zp
     * @date: 2023/1/17 19:08
     * @return BasicErrorController
     */
    @Bean
    public BasicErrorController basicErrorController(){
        ErrorProperties errorProperties = new ErrorProperties();
        // 设置开启异常信息打印
        errorProperties.setIncludeException(true);
        return new BasicErrorController(new DefaultErrorAttributes(), errorProperties);
    }
    /**
     * @description:  注入error视图对象
     * @author zp
     * @date: 2023/1/17 19:23
     * @return View
     */
    @Bean
    public View error(){
        return new MyView();
    }
    /**
     * @description:  设置beanName 视图解析器
     * @author zp
     * @date: 2023/1/17 19:25
     * @return ViewResolver
     */
    @Bean
    public ViewResolver viewResolver(){
//        InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
//        internalResourceViewResolver.setPrefix("/templates/");
//        internalResourceViewResolver.setSuffix(".html");
//        return internalResourceViewResolver;
        return  new BeanNameViewResolver();
    }


}
